package com.iwdnb.gkgz.common.quota;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import com.alibaba.fastjson.JSON;

import com.google.common.collect.Lists;
import com.iwdnb.gkgz.common.model.dto.StockDayData;
import com.iwdnb.gkgz.common.utils.BigDecimalUtils;
import com.iwdnb.gkgz.common.utils.StockUtils;

/**
 * OBV（On-Balance Volume，累积能量线）是一个常用的技术分析指标，通过市场成交量的变化来反映价格趋势。OBV指标的计算可以分为以下几个步骤：
 *
 * 如果当天的收盘价高于前一天的收盘价，则当日的OBV = 前一日的OBV + 当日的成交量。
 * 如果当天的收盘价低于前一天的收盘价，则当日的OBV = 前一日的OBV - 当日的成交量。
 * 如果当天的收盘价等于前一天的收盘价，则当日的OBV = 前一日的OBV。
 */
public class OBVNewIndicator {

    public static final String QUOTA_NAME = "obv";

    public static void calculateOBV(List<StockDayData> stockDayDataList) {
        //计算成交量比
        //VolumeRatioIndicator.calculateVolumeRatio(stockDayDataList);
        //List<Double> obvList = calculateExpOBV(stockDayDataList, 0.35);
        List<Double> obvList = doCalculateOBV(stockDayDataList);

        int size = stockDayDataList.size();
        for (int i = 0; i < size; i++) {
            StockDayData data = stockDayDataList.get(i);
            Double obv = obvList.get(i);
            double tradeNum = data.getTradeNum();
            BigDecimal volumeRaio = StockUtils.getStockQuota(data, VolumeRatioIndicator.QUOTA_NAME);
            if (Objects.isNull(volumeRaio)) {
                volumeRaio = BigDecimal.ONE;
            }
            tradeNum = tradeNum / volumeRaio.doubleValue();
            if (tradeNum == 0) {
                tradeNum = data.getTradeNum();
            }
            //BigDecimal obvData = BigDecimalUtils.divide(obv.toString(), tradeNum + "");
            StockUtils.setStockQuota(data, QUOTA_NAME, obv);
        }

    }

    private static long getAverageTradeNum(List<StockDayData> stockDayDataList) {
        if (stockDayDataList.size() > 100) {
            stockDayDataList = stockDayDataList.subList(0, 100);
        }
        long sum = stockDayDataList.stream()
            .mapToLong(StockDayData::getTradeNum)
            .sum();
        return sum / stockDayDataList.size();
    }

    public static List<Double> doCalculateOBV(List<StockDayData> stockDataList) {
        List<Double> obvList = new ArrayList<>();
        if (stockDataList == null || stockDataList.isEmpty()) {
            return obvList;
        }

        BigDecimal prevClose = stockDataList.get(0).getClosePrice();
        double obv = 0.0;

        for (int i = 0; i < stockDataList.size(); i++) {
            StockDayData currentData = stockDataList.get(i);
            double closePrice = currentData.getClosePrice().doubleValue();
            long volume = currentData.getTradeNum();
            //if (i > 0) {
            //    if (closePrice > prevClose.doubleValue()) {
            //        obv += volume;
            //    } else if (closePrice < prevClose.doubleValue()) {
            //        obv -= volume * 1.5;
            //    }
            //    // 如果收盘价没有变化，OBV保持不变
            //}
            //使用多空比率净额优化成交量
            if (i > 0) {
                //一字板时还是根据价格高低计算obv
                if (BigDecimalUtils.eq(currentData.getMaxPrice(), currentData.getMinPrice())) {
                    if (BigDecimalUtils.isGe(currentData.getMaxPrice(), prevClose)) {
                        obv += volume;
                    } else {
                        obv -= volume;
                    }
                } else {
                    double maxPrice = currentData.getMaxPrice().doubleValue();
                    double minPrice = currentData.getMinPrice().doubleValue();
                    //多空比率净额= [（收盘价－最低价）－（最高价-收盘价）] ÷（ 最高价－最低价）×V
                    double v = (closePrice - minPrice) - (maxPrice - closePrice);
                    double t = maxPrice - minPrice;
                    if (v > 0) {
                        volume = (long)(volume * 0.9);
                    }
                    v = v / t * volume;
                    obv += v;
                }
            }
            obvList.add(obv);
            prevClose = currentData.getClosePrice();
        }

        return obvList;
    }

    public static List<Double> calculateExpOBV(List<StockDayData> stockDataList, double alpha) {
        List<Double> obvList = doCalculateOBV(stockDataList);
        List<Double> expObvList = new ArrayList<>();

        if (obvList.isEmpty()) {
            return expObvList;
        }

        double expObv = obvList.get(0);
        expObvList.add(expObv);

        for (int i = 1; i < obvList.size(); i++) {
            expObv = alpha * obvList.get(i) + (1 - alpha) * expObv;
            expObvList.add(expObv);
        }

        return expObvList;
    }

    public static void main(String[] args) {
        // 示例数据，实际数据应该从文件或数据库获取

        List<StockDayData> stockDayDataList = StockUtils.getHistoryData("sh600418", "2015-01-01", "2018-01-01");
        calculateOBV(stockDayDataList);
        System.out.println("OBV: " + JSON.toJSONString(stockDayDataList));
    }

    private static StockDayData createStockDayData(BigDecimal closePrice, String max, String min, int tradeNum) {
        StockDayData stockDayInfo = new StockDayData();
        stockDayInfo.setClosePrice(closePrice);
        stockDayInfo.setMaxPrice(new BigDecimal(max));
        stockDayInfo.setMinPrice(new BigDecimal(min));
        stockDayInfo.setTradeNum(tradeNum);
        return stockDayInfo;
    }
}
